package cn.datawin.spider.seletor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import us.codecraft.xsoup.Xsoup;

/**
 * Selectable html.<br>
 * 
 * @author panmg
 * @since 0.1.0
 */
public class Html extends AbstractSelectable implements Cloneable{
	
	private Logger logger = LoggerFactory.getLogger(getClass());

	private Elements elements;
	
	public Html() {
	}
	
	public Html(String text) {
		try {
			this.elements = Jsoup.parse(text).children();
		} catch (Exception e) {
			logger.warn("parse document error ", e);
		}
	}
	
	public void init(String text){
		try {
			this.elements = Jsoup.parse(text).children();
		} catch (Exception e) {
			logger.warn("parse document error ", e);
		}
	}

	public void setElements(Elements elements) {
		this.elements = elements;
	}
	
	public void addElement(Element element){
		this.elements.add(element);
	}

	public Elements getElements() {
		return elements;
	}
	
	public static Html create(String text) {
		return new Html(text);
	}

	@Override
	public Selectable xpath(String xpath) {
		Elements es = new Elements();
		for (Element e : elements) {
			Elements ess = Xsoup.compile(xpath).evaluate(e).getElements();
			if (ess == null || ess.size() == 0)
				continue;
			es.addAll(ess);
		}
		setElements(es);
		return this;
	}

	@Override
	public Selectable $(String selector) {
		Elements es = new Elements();
		for (Element e : elements) {
			Elements ess = e.select(selector);
			if (ess == null || ess.size() == 0)
				continue;
			es.addAll(ess);
		}
		setElements(es);
		return this;
	}
	
	@Override
	public Selectable first(){
		Elements es = new Elements();
		if(null!=elements.first()){
			es.add(elements.first());
		}
		setElements(es);
		return this;
	}
	
	@Override
	public Selectable last(){
		Elements es = new Elements();
		if(null!=elements.last()){
			es.add(elements.last());
		}
		setElements(es);
		return this;
	}
	

	@Override
	public String regex(String regexStr) {
		return regex(regexStr, 1);
	}
	
	public List<String> _regexAll(String regexStr, int group) {
		Pattern regex = Pattern.compile(regexStr, Pattern.DOTALL
				| Pattern.CASE_INSENSITIVE);
		Matcher matcher = regex.matcher(elements.toString());
		boolean find = matcher.find();
		List<String> groups = new ArrayList<String>();
		if (!find) {
			matcher = regex.matcher(elements.text());
			if (matcher.find()) {
				groups.add(matcher.group(group));
			}
		} else {
			groups.add(matcher.group(group));
		}
		while (matcher.find()) {
			groups.add(matcher.group(group));
		}
		return groups;
	}

	@Override
	public String regexAll(String regexStr) {
		List<String> groups = _regexAll(regexStr, 1);
		return StringUtils.join(groups.toArray(), "^|");
	}

	@Override
	public String regex(String regexStr, int group) {
		List<String> groups = _regexAll(regexStr, group);
		return groups.size() == 0 ? "" : groups.get(0);
	}

	@Override
	public String toString() {
		return elements.toString();
	}

	@Override
	public Selectable smartContent() {
		return null;
	}

	@Override
	public Selectable links() {
		xpath("//a/@href");
		return this;
	}


	@Override
	protected Elements getSourceTexts() {
		return getElements();
	}

	@Override
	public String html() {
		return elements.html();
	}

	@Override
	public String text() {
		StringBuilder sb = new StringBuilder();
		for (Element element : elements) {
			if(element.getAllElements()==null ||element.getAllElements().size()==0){
				if (sb.length() != 0)
					sb.append("^|");
				sb.append(element.text());
				continue;
			}
			for(Element element1 :element.getAllElements()){
				if (sb.length() != 0)
					sb.append("^|");
				sb.append(element1.ownText());
			}
		}
		return sb.toString();
	}

	@Override
	public String attr(String attr) {
		StringBuilder sb = new StringBuilder();
		for (Element e : elements) {
			if (sb.length() != 0) {
				sb.append("^|");
			}
			sb.append(e.attr(attr));
		}
		return sb.toString();
	}
	
	
	@Override
	public String jsonPath(String path) {
		List<String> list =  jsonPathList(path);
		if(list.size() == 0) return "";
		return StringUtils.join(list.toArray(),"^|");
	}
	
	@Override
	public List<String> jsonPathList(String path) {
		return super.jsonPathList(elements.text(), path);
	}
	
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
